package com.ruoyi.project.service.impl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.druid.support.opds.udf.ExportConditions;
import com.ruoyi.base.domain.ComponentClassification;
import com.ruoyi.base.service.IComponentClassificationService;
import com.ruoyi.base.util.ExcelExp;
import com.ruoyi.base.util.ExcelUtilManySheet;
import com.ruoyi.base.util.GenCodeUtils;
import com.ruoyi.base.util.SystemInfo;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.common.utils.uuid.Seq;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.contract.domain.ContractInfo;
import com.ruoyi.contract.domain.ContractPlanInfo;
import com.ruoyi.contract.mapper.ContractInfoMapper;
import com.ruoyi.generator.util.GenUtils;
import com.ruoyi.project.domain.CompomentInfo;
import com.ruoyi.project.domain.ProjectModelInfo;
import com.ruoyi.project.mapper.CompomentInfoMapper;
import com.ruoyi.project.mapper.ProjectModelInfoMapper;
import com.ruoyi.project.service.ICompomentInfoService;
import com.ruoyi.project.vo.CompomentInfoListVO;
import com.ruoyi.project.vo.ExportCompomentInfo;
import com.ruoyi.project.vo.FloorCompomentInfo;
import com.ruoyi.project.vo.FloorInfo;
import io.swagger.models.auth.In;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.ruoyi.project.mapper.ProjectInfoMapper;
import com.ruoyi.project.domain.ProjectInfo;
import com.ruoyi.project.service.IProjectInfoService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;

/**
 * 项目信息Service业务层处理
 *
 * @author ruoyi
 * @date 2022-08-26
 */
@Service
public class ProjectInfoServiceImpl implements IProjectInfoService {
    @Autowired
    private ProjectInfoMapper projectInfoMapper;

    @Autowired
    private ProjectModelInfoMapper projectModelInfoMapper;

    @Autowired
    private IComponentClassificationService componentClassificationService;

    @Autowired
    private ContractInfoMapper contractInfoMapper;


    /**
     * 查询项目信息
     *
     * @param id 项目信息主键
     * @return 项目信息
     */
    @Override
    public ProjectInfo selectProjectInfoById(Long id) {
        return projectInfoMapper.selectProjectInfoById(id);
    }

    /**
     * 查询项目信息列表
     *
     * @param projectInfo 项目信息
     * @return 项目信息
     */
    @Override
    public List<ProjectInfo> selectProjectInfoList(ProjectInfo projectInfo) {
        return projectInfoMapper.selectProjectInfoList(projectInfo);
    }

    /**
     * 新增项目信息
     *
     * @param projectInfo 项目信息
     * @return 结果
     */
    @Override
    public int insertProjectInfo(ProjectInfo projectInfo) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        projectInfo.setCreateBy(user.getUserName());
        projectInfo.setCreateTime(DateUtils.getNowDate());
        projectInfo.setProjectNo(GenCodeUtils.getProjectNo());
        List<ProjectInfo> projectInfoList = projectInfoMapper.getProjectInfo(projectInfo.getContractNo());
        if (!projectInfoList.isEmpty()){
            throw new ServiceException("合同{" + projectInfo.getContractNo() +"}已被其他项目绑定,确认后再试!");
        }
        return projectInfoMapper.insertProjectInfo(projectInfo);
    }

    /**
     * 修改项目信息
     *
     * @param projectInfo 项目信息
     * @return 结果
     */
    @Override
    public int updateProjectInfo(ProjectInfo projectInfo) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        projectInfo.setUpdateBy(user.getUserName());
        projectInfo.setUpdateTime(DateUtils.getNowDate());
        return projectInfoMapper.updateProjectInfo(projectInfo);
    }

    /**
     * 批量删除项目信息
     *
     * @param ids 需要删除的项目信息主键
     * @return 结果
     */
    @Override
    public int deleteProjectInfoByIds(Long[] ids) {
        return projectInfoMapper.deleteProjectInfoByIds(ids);
    }

    /**
     * 删除项目信息信息
     *
     * @param id 项目信息主键
     * @return 结果
     */
    @Override
    public int deleteProjectInfoById(Long id) {
        return projectInfoMapper.deleteProjectInfoById(id);
    }

    /**
     * 获取项目下楼栋列表
     *
     * @param projectNo
     * @return
     */
    @Override
    public List<String> getFloorList(String projectNo) {
        return projectInfoMapper.getFloorList(projectNo);
    }

    /**
     * 创建楼栋
     *
     * @param floorInfo
     * @return
     */
    @Override
    public int createFloor(FloorInfo floorInfo) {
        //创建一个空的楼栋信息
        ProjectModelInfo projectModelInfo = new ProjectModelInfo();
        projectModelInfo.setProjectNo(floorInfo.getProjectNo());
        projectModelInfo.setBuildNo(floorInfo.getBuildNo());
        List<ProjectModelInfo> modelInfoList = projectModelInfoMapper.selectProjectModelInfoList(projectModelInfo);
        if (StringUtils.isBlank(floorInfo.getChangeBuildNo())) {
            if (modelInfoList.size() > 0) throw new ServiceException("该楼栋信息已存在，无法重复添加！");
            return projectModelInfoMapper.insertProjectModelInfo(projectModelInfo);
        }
        //更改
        ProjectModelInfo projectModelInfo1 = modelInfoList.get(0);
        projectModelInfo1.setBuildNo(floorInfo.getChangeBuildNo());
        return projectModelInfoMapper.updateProjectModelInfo(projectModelInfo1);
    }

    /**
     * 复制楼栋
     *
     * @param floorInfo
     * @return
     */
    @Override
    public int copyFloor(FloorInfo floorInfo) {
        //复制前，删除这个楼栋下所有构件
        projectModelInfoMapper.deleteProjectModelInfoByFloorInfo(floorInfo);
        return projectModelInfoMapper.copyFloor(floorInfo);
    }

    //获取楼层构件——楼层表
    @Override
    public AjaxResult getFloorLayer(FloorInfo floorInfo) {
        List<FloorCompomentInfo> floorLayer = projectModelInfoMapper.getFloorLayer(floorInfo);
        //获取楼栋数量
        List<String> floorList = projectModelInfoMapper.getFloorNum(floorInfo);

        //获取构件数量
        List<String> compomentList = projectModelInfoMapper.getCompomentNum(floorInfo);
        String[][] dataTable = new String[compomentList.size()+1][floorList.size()+2];

        //楼栋坐标列
        Map<String, Integer> floorMap = new HashedMap();
        for (int i = 0; i < floorList.size(); i++) {
            String s = floorList.get(i);
            dataTable[0][i+2] = s;
            floorMap.put(s,i+2);
        }
        //构件坐标行
        Map<String,Integer> compomentMap = new HashMap<>();
        for (int i = 0; i < compomentList.size(); i++) {
            String s = compomentList.get(i);
            dataTable[i+1][0] = "类型";
            dataTable[i+1][1] = s;
            compomentMap.put(s,i+1);
        }
        //构件类型
        LinkedHashMap<String, Integer> compomentLink = new LinkedHashMap<>();
        //解析
        for (int i = 0; i < floorLayer.size(); i++) {
            FloorCompomentInfo floorCompomentInfo = floorLayer.get(i);
            Integer floorNum = floorMap.get(floorCompomentInfo.getFloor());
            Integer compomentNum = compomentMap.get(floorCompomentInfo.getCompomentName());
            dataTable[compomentNum][floorNum] = String.valueOf(floorCompomentInfo.getCount());
            if (compomentLink.containsKey(floorCompomentInfo.getCompomentName())){
                compomentLink.put(floorCompomentInfo.getCompomentName(),compomentLink.get(floorCompomentInfo.getCompomentName())+1);
            }
            compomentLink.put(floorCompomentInfo.getCompomentName(),1);
        }
        AjaxResult success = AjaxResult.success();
        success.put("compomentType",compomentLink);
        success.put("dataTable",dataTable);
        return success;
    }


    @Override
    public List<CompomentInfo> getCompomentList(FloorInfo floorInfo) {
        List<CompomentInfo> compomentList = projectModelInfoMapper.getCompomentList(floorInfo);
        return compomentList;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class,ServiceException.class})
    public int addWidget(FloorInfo floorInfo) {
        //判断楼层范围合理性
        int min = changeFloor(floorInfo.getMinFloor());
        int max = changeFloor(floorInfo.getMaxFloor());
        if (min > max) {
            throw new ServiceException("楼层范围不合理，确认后再次提交！");
        }
        List<ProjectModelInfo> modelInfoList = new ArrayList<>();
        for (FloorInfo.Info info : floorInfo.getInfo()) {
            for (int i = min; i <= max; i++) {
                ProjectModelInfo modelInfo = new ProjectModelInfo();
                //构件是否存在
                modelInfo.setProjectNo(floorInfo.getProjectNo());
                modelInfo.setBuildNo(floorInfo.getBuildNo());
                modelInfo.setCompomentNo(info.getCompomentNo());
                modelInfo.setFloor(String.valueOf(min));
                List<ProjectModelInfo> dbModelInfoList = projectModelInfoMapper.selectProjectModelInfoList(modelInfo);
                if (dbModelInfoList.size() >0){
                    modelInfo = dbModelInfoList.get(0);
                    modelInfo.setCount(modelInfo.getCount()+info.getCount());
                    projectModelInfoMapper.updateProjectModelInfo(modelInfo);
                    continue;
                }
                modelInfo.setCount(info.getCount());
                modelInfoList.add(modelInfo);
            }
        }
        if (modelInfoList.isEmpty()){
            return 1;
        }
        return projectModelInfoMapper.batchInsert(modelInfoList);
    }

    private int changeFloor(String floor) {
        try {
            return Integer.parseInt(floor);
        }catch (NumberFormatException e){
            throw new ServiceException("楼层格式不对，请确定是否未数字!");
        }
    }


    @Override
    public int delFloor(FloorInfo floorInfo) {
        return projectModelInfoMapper.delFloor(floorInfo);
    }

    /**
     * 复制层
     */
    public int copyLayer(FloorInfo floorInfo){
        //复制前，删除这层下所有构件
        projectModelInfoMapper.delLayer(floorInfo);
        return projectModelInfoMapper.copyLayer(floorInfo);
    }

    /**
     * 删除层
     * @param floorInfo
     * @return
     */
    public int delLayer(FloorInfo floorInfo){
        return projectModelInfoMapper.delLayer(floorInfo);
    }

    /**
     * 模板下载
     *
     * @return
     */
    @Override
    public void templateDownload(HttpServletResponse response) throws IOException {
        List<ComponentClassification> componentClassifications = componentClassificationService.selectComponentClassificationList(new ComponentClassification());
        String[] textlist = new String[componentClassifications.size()];
        for (int i = 0; i < componentClassifications.size(); i++) {
            textlist[i] = componentClassifications.get(i).getComponenType();
        }
        //获取模板文件
        InputStream in = this.getClass().getClassLoader().getResourceAsStream(SystemInfo.getSeparator() + "template" + SystemInfo.getSeparator() + "project_template.xlsx");
        //构建模板
        XSSFWorkbook sheets = new XSSFWorkbook(in);//读取文件
        //获取sheet
        XSSFSheet sheet = sheets.getSheetAt(0);
        ExcelUtil excelUtil = new ExcelUtil(this.getClass());
        excelUtil.setPromptOrValidation(sheet,textlist,"",1,1,0,0);

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment; filename=project_template.xlsx");
        sheets.write(response.getOutputStream());
    }

    @Override
    @Transactional
    public AjaxResult templateExport(MultipartFile file, String projectNo,String buildNo) throws IOException {
        //建模数据导入数据结果集合
        List<ProjectModelInfo> modelInfoList = new ArrayList<>();
        Workbook sheets = WorkbookFactory.create(file.getInputStream());
        Sheet sheet = sheets.getSheetAt(0);
        if (sheet == null) {
            throw new IOException("文件sheet不存在");
        }
        //获取楼层数量，第二行第三列开始进入列获取，
        List<String> floorNum = new ArrayList<>();
        Row row = sheet.getRow(0);
        for (int i = 2; i < row.getLastCellNum(); i++) {
            Cell cell = row.getCell(i);
            if (StringUtils.isBlank(getCellValue(cell))) break;
            floorNum.add(getCellValue(cell));
        }
        //获取构件分类
        List<ComponentClassification> componentClassifications = componentClassificationService.selectComponentClassificationList(new ComponentClassification());
        Map<String, String> classificationMap = componentClassifications.stream().collect(Collectors.toMap(ComponentClassification::getComponenType, ComponentClassification::getCategoryCode));
        //需要被创建构件
        List<CompomentInfo> creatCompomentList = new ArrayList<>();
        //构件
        FloorInfo floorInfo = new FloorInfo();
        floorInfo.setProjectNo(projectNo);
        List<CompomentInfo> compomentList = projectModelInfoMapper.getCompomentList(floorInfo);
        Map<String, String> compomentMap = new HashMap<>();
        for (CompomentInfo compomentInfo : compomentList) {
            compomentMap.put(compomentInfo.getCompomentName(), compomentInfo.getCompomentNo());
        }
        //获取构件数量，第二行第二列开始进入行获取，
        for (int i = 1; i < sheet.getLastRowNum(); i++) {
            Row row1 = sheet.getRow(i);
            //获取构件分类类别
            String componentType = row1.getCell(0).getStringCellValue();
            if(StringUtils.isBlank(componentType)) break;
            //获取构件分类编号
            if (!classificationMap.containsKey(componentType)) throw new ServiceException("构件类别未找到,请维护构件分类(" + componentType + ")!");
            //构件类别名字
            String componentName = getCellValue( row1.getCell(1));
            //构件空，认为结束
            if (StringUtils.isBlank(componentName)) break;

            //判断构件
            //构件编号
            String componentNo;
            //判定构件是否存在
            if (!compomentMap.containsKey(componentName)){
                CompomentInfo compomentInfo = new CompomentInfo();
                compomentInfo.setProjectNo(projectNo);
                compomentInfo.setCompomentNo(UUID.fastUUID().toString(true));
                //构件分类类别
                compomentInfo.setCompomentType(componentType);
                compomentInfo.setCompomentName(componentName);
                creatCompomentList.add(compomentInfo);
                //维护模型构件编号
                componentNo = compomentInfo.getCompomentNo();
            }else {
                //维护模型构件编号
                componentNo = compomentMap.get(componentName);
            }

            //构件建模数据
            for (int r = 0; r < floorNum.size(); r++) {
                //数量
                if (StringUtils.isBlank(getCellValue(row1.getCell(r+2)))) continue;
                ProjectModelInfo modelInfo = new ProjectModelInfo();
                //项目编号
                modelInfo.setProjectNo(projectNo);
                //楼栋编号
                modelInfo.setBuildNo(buildNo);
                //楼层编号
                modelInfo.setFloor(floorNum.get(r));
                //构件编号
                modelInfo.setCompomentName(componentName);
                modelInfo.setCompomentNo(componentNo);
                //构件分类
                modelInfo.setCompomentType(componentType);
                //数量
                modelInfo.setCount(Long.valueOf(getCellValue(row1.getCell(r+2))));
                modelInfoList.add(modelInfo);
            }
        }
        saveImportExcel(modelInfoList,creatCompomentList,projectNo,buildNo);
        return null;
    }

    //将数据导入库中
    @Transactional
    public void saveImportExcel(List<ProjectModelInfo> modelInfoList,List<CompomentInfo> creatCompomentList,String projectNo,String buildNo){        //删除楼栋下全部数据
        FloorInfo floorInfo = new FloorInfo();
        floorInfo.setProjectNo(projectNo);
        floorInfo.setBuildNo(buildNo);
        delFloor(floorInfo);
        //导入构件
        if (modelInfoList.size() > 0)projectModelInfoMapper.batchInsert(modelInfoList);
        //导入模型
        if (creatCompomentList.size() >0) projectModelInfoMapper.batchCompomentInsert(creatCompomentList);

    }


    private String getCellValue(Cell cell){
        String cellValue = "";
        // 以下是判断数据的类型
        switch (cell.getCellType()) {
            case NUMERIC: // 数字
                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    cellValue = sdf.format(org.apache.poi.ss.usermodel.DateUtil.getJavaDate(cell.getNumericCellValue())).toString();
                } else {
                    DataFormatter dataFormatter = new DataFormatter();
                    cellValue = dataFormatter.formatCellValue(cell);
                }
                break;
            case STRING: // 字符串
                cellValue = cell.getStringCellValue();
                break;
            case BOOLEAN: // Boolean
                cellValue = cell.getBooleanCellValue() + "";
                break;
            case FORMULA: // 公式
                cellValue = cell.getCellFormula() + "";
                break;
            case BLANK: // 空值
                cellValue = "";
                break;
            case ERROR: // 故障
                cellValue = "非法字符";
                break;
            default:
                cellValue = "未知类型";
                break;
        }
        return cellValue;
    }

    /**
     * 项目下构件导出
     * @param response
     * @param projectInfo
     */
    public void exportMember(HttpServletResponse response, ProjectInfo projectInfo) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        if (StringUtils.isBlank(projectInfo.getProjectNo())){
            throw new ServiceException("项目编号为空,无法导出!");
        }
        List<String> floorList = getFloorList(projectInfo.getProjectNo());
        List<ExcelExp> sheetList = new ArrayList<ExcelExp>();
        for (String buildNo : floorList) {
            //创建工作表对象
            FloorInfo floorInfo = new FloorInfo();
            floorInfo.setProjectNo(projectInfo.getProjectNo());
            floorInfo.setBuildNo(buildNo);
            List<ExportCompomentInfo> exportCompomentInfo = projectModelInfoMapper.getExportCompomentInfo(projectInfo.getProjectNo(), buildNo);
            ExcelExp excelExp = new ExcelExp(buildNo, exportCompomentInfo, ExportCompomentInfo.class);
            sheetList.add(excelExp);
        }
        ExcelUtilManySheet<List<ExcelExp>> util2 = new ExcelUtilManySheet<List<ExcelExp>>(sheetList);
        util2.exportExcelManySheet(response, sheetList,true);
    }

    public List<ContractInfo> getContractInfoList(){
        return projectInfoMapper.getContractInfoList();
    }

    @Override
    public ContractInfo selectContractInfoById(Long id) {
        return contractInfoMapper.selectContractInfoById(id);
    }
}
